/////////////////////////////////////////////////////////////////////////////// 
//// FileName: iPN_Proto.h
//// Description: iPN Protocal header file
//// Author: Charlie Chang (sengfu@gmail.com)
//// All right reserved 2014.
////  Revision History:
////      Create Date: 2014/08/27
////      
////////////////////////////////////////////////////////////////////////////////

#ifndef __INCLUDE_FILE_iPN_PROTOCOL
#define __INCLUDE_FILE_iPN_PROTOCOL

#include "iPN_Type.h"
#define iPN_PROTO_MAX_PACKET_SIZE 			1440 
#define iPN_PROTO_EVENT_NAME_SIZE				32
#define iPN_PROTO_TOKEN_SIZE					160  
#define iPN_PROTO_POST_ADDITIONALINFO_SIZE 	128
#define iPN_PROTO_VERSION 						0x01 
#define iPN_PROTO_MAGICWORD 					0x0118 
#define iPN_PROTO_QUERY_TOKEN_PASSWORD_MAX_SIZE 32

typedef enum {
//// Hello Message
	iPN_MSG_HELLO = 0x02,
	iPN_MSG_HELLO_ACK = 0x03,

//// Publish Message
	iPN_MSG_PUBLISH = 0x10,
	iPN_MSG_PUBLISH_ACK = 0x11,

//// UnPublish
	iPN_MSG_UNPUBLISH = 0x12,
	iPN_MSG_UNPUBLISH_ACK = 0x13,

//// Subacribe
	iPN_MSG_SUBSCRIBE = 0x20,
	iPN_MSG_SUBSCRIBE_ACK = 0x21,
//// UnSubscribe
	iPN_MSG_UNSUBSCRIBE = 0x22,
	iPN_MSG_UNSUBSCRIBE_ACK = 0x23,

//// Post
	iPN_MSG_POST = 0x30,
	iPN_MSG_POST_ACK = 0x31,

	//// QueryToken
	iPN_MSG_QUERYTOKEN = 0x32,
	iPN_MSG_QUERYTOKEN_ACK = 0x33

} ENUM_iPN_UDP_MESSAGE;

//// The iPN UDP Protocol Header
typedef struct {
	UINT16 MagicWord; //// Must be 0x0118 
	UCHAR ProtoVersion; //// the Protocol version
	UCHAR MsgType; //// refer to ENUM_iPN_UDP_MESSAGE
	UINT16 EffectiveDataSize; //// 0 ~ (iPN_PROTO_MAX_PACKET_SIZE - sizeof(st_iPN_UDPHeader))
	UINT16 Counter; //// 0 ~ 0xFFFF, Every iPN Packet increase 1
	UINT16 RandNumber; ///// A random number between 0~0xFFFF, (What for?? after AES encryption, every packet header will differ), Receiver shall ignore this.
	UCHAR Reserved[6]; //// Reserved, must be 0
} st_iPN_UDPHeader;

//// MSG_HELLO 
//// (No Data)

//// MSG_HELLO_ACK
typedef struct {
	struct sockaddr_in YourWanAddr;
	UINT32 nJob;
	//CHAR Reserved[12];
} st_iPN_HelloAck;

//// iPN_MSG_PUBLISH
typedef struct {
	CHAR Prefix[8];
	UINT32 SerialNumber;
	CHAR CheckCode[8];
	CHAR AuthCode[12];
	CHAR EventName[iPN_PROTO_EVENT_NAME_SIZE];
	UINT32 TimeStamp;
	UINT32 bFlagOpen;
	CHAR QueryTokenPassword[iPN_PROTO_QUERY_TOKEN_PASSWORD_MAX_SIZE];
} st_iPN_Publish;

//// iPN_MSG_PUBLISH_ACK
typedef struct {
	CHAR Prefix[8];
	UINT32 SerialNumber;
	CHAR CheckCode[8];
	CHAR EventName[iPN_PROTO_EVENT_NAME_SIZE];
	CHAR PublishResult; //// 0: Publish OK, Publish
	CHAR Reserved[3];
	CHAR SubscribeToken[iPN_PROTO_TOKEN_SIZE];
	CHAR PostToken[iPN_PROTO_TOKEN_SIZE];
} st_iPN_PublishAck;

//// iPN_MSG_UNPUBLISH
typedef struct {
	CHAR Prefix[8];
	UINT32 SerialNumber;
	CHAR CheckCode[8];
	CHAR AuthCode[12];
	CHAR EventName[iPN_PROTO_EVENT_NAME_SIZE];
} st_iPN_UnPublish;

//// iPN_MSG_UNPUBLISH_ACK
typedef struct {
	CHAR Prefix[8];
	UINT32 SerialNumber;
	CHAR CheckCode[8];
	CHAR EventName[iPN_PROTO_EVENT_NAME_SIZE];
	CHAR UnPublishResult; //// 0: Publish OK, Publish
	CHAR Reserved[3];
} st_iPN_UnPublishAck;

//// iPN_MSG_SUBSCRIBE,  st_iPN_Subscribe + SubscribeDescription (MySQL cmd)
typedef struct {
	CHAR SubscribeToken[iPN_PROTO_TOKEN_SIZE];
	UINT32 SubscriberID;
	UINT16 SubscribeDescriptionSize;
	CHAR Reserved[2];
	UINT32 TimeStamp;
	CHAR TableName[128];
} st_iPN_Subscribe;

//// iPN_MSG_SUBSCRIBE_ACK 
typedef struct {
	CHAR SubscribeToken[iPN_PROTO_TOKEN_SIZE];
	CHAR SubscribeResult;
	CHAR Reserved[3];
	UINT32 SubscriberID;
} st_iPN_SubscribeAck;

//// iPN_MSG_UNSUBSCRIBE 
typedef struct {
	CHAR SubscribeToken[iPN_PROTO_TOKEN_SIZE];
	UINT32 SubscriberID;
	CHAR TableName[128];
} st_iPN_UnSubscribe;

//// iPN_MSG_UNSUBSCRIBE_ACK 
typedef struct {
	CHAR SubscribeToken[iPN_PROTO_TOKEN_SIZE];
	CHAR UnSubscribeResult;
	CHAR Reserved[3];
} st_iPN_UnSubscribeAck;

//// iPN_MSG_POST
typedef struct {
	CHAR PostToken[iPN_PROTO_TOKEN_SIZE];
	UINT32 TimeStamp;
	CHAR AdditionalInfo[iPN_PROTO_POST_ADDITIONALINFO_SIZE];
} st_iPN_Post;

//// iPN_MSG_POST_ACK
typedef struct {
	CHAR PostToken[iPN_PROTO_TOKEN_SIZE];
	CHAR PostResult;
	CHAR Reserved[3];
} st_iPN_PostAck;

//// iPN_MSG_QUERYTOKEN
typedef struct {
	CHAR DID[32]; //8+4+8+2+2
	CHAR EventName[iPN_PROTO_EVENT_NAME_SIZE];
	UINT32 TimeStamp;
	CHAR QueryTokenPassword[iPN_PROTO_QUERY_TOKEN_PASSWORD_MAX_SIZE];
} st_iPN_QueryToken;

//// iPN_MSG_QUERYTOKEN_ACK
typedef struct {
	CHAR DID[32];
	CHAR EventName[iPN_PROTO_EVENT_NAME_SIZE];
	CHAR SubscribeToken[iPN_PROTO_TOKEN_SIZE];
	CHAR QueryTokenResult;
	CHAR Reserved[3];
} st_iPN_QueryTokenAck;

//// Post Notify .... This is not part of iPN UDP Protocol, but Data structure for Portal to notify NotifyServer a Event is posted
typedef struct {
	UINT32 TimeStamp;
	UINT32 SubscriberID;
	CHAR AdditionalInfo[iPN_PROTO_POST_ADDITIONALINFO_SIZE];
} st_Post_Notify;

//// **************************** Function declare ********************************
//// host & network addr translation 
//void htonAddr(const struct sockaddr_in *src, struct sockaddr_in *result);
//void ntohAddr(const struct sockaddr_in *src, struct sockaddr_in *result);
//// for iPN UDP Header
void iPN_Proto_Write_Header(st_iPN_UDPHeader* pH, const UCHAR MsgType,
		const UINT16 EffectiveDataSize, const UINT16 Counter);
INT32 iPN_Proto_Read_Header(const st_iPN_UDPHeader *pH, UCHAR *MsgType,
		UINT16 *EffectiveDataSize, UINT16 *Counter);
////iPN UDP Packet Receive
INT32 iPN_Proto_Recv_ALL(const INT32 skt, const CHAR *AESKey,
		struct sockaddr_in *FromAddr, UINT32 TimeOut_ms, UCHAR *MsgType,
		UINT16 *EffectiveDataSize, CHAR *Data, UINT16 MaxDataSize,
		UINT16 *Counter);
//// Hello 
INT32 iPN_Proto_Send_Hello(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const UINT16 Counter);
//// Hello ACK
void iPN_Proto_Write_HelloAck(st_iPN_HelloAck *pHelloAck,
		const struct sockaddr_in *YourWanAddr, const UINT32 nJob);
void iPN_Proto_Read_HelloAck(const st_iPN_HelloAck *pHelloAck,
		struct sockaddr_in *YourWanAddr, UINT32 *nJob);
INT32 iPN_Proto_Send_HelloAck(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const struct sockaddr_in *YourWanAddr,
		const UINT32 nJob, const UINT16 Counter);
//// Publish
void iPN_Proto_Write_Publish(st_iPN_Publish *pPublish, const CHAR *Prefix,
		const UINT32 SerialNumber, const CHAR *CheckCode, const CHAR*AuthCode,
		const CHAR *EventName, const UINT32 TimeStamp, const int bFlagOpen,
		const CHAR* QueryTokenPassword);
void iPN_Proto_Read_Publish(const st_iPN_Publish *pPublish, CHAR *Prefix,
		UINT32 *SerialNumber, CHAR *CheckCode, CHAR *AuthCode, CHAR *EventName,
		UINT32 *TimeStamp, UINT32 *bFlagOpen, CHAR* QueryTokenPassword);
INT32 iPN_Proto_Send_Publish(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *Prefix,
		const UINT32 SerialNumber, const CHAR *CheckCode, const CHAR*AuthCode,
		const CHAR *EventName, const UINT32 TimeStamp, const UINT16 Counter,
		const int bFlagOpen, const CHAR* QueryTokenPassword);
//// PublishAck
void iPN_Proto_Write_PublishAck(st_iPN_PublishAck *pPublishAck,
		const CHAR *Prefix, const UINT32 SerialNumber, const CHAR *CheckCode,
		const CHAR *EventName, const CHAR PublishResult,
		const CHAR *SubscribeToken, const CHAR *PostToken);
void iPN_Proto_Read_PublishAck(const st_iPN_PublishAck *pPublishAck,
		CHAR *Prefix, UINT32 *SerialNumber, CHAR *CheckCode, CHAR *EventName,
		CHAR *PublishResult, CHAR *SubscribeToken, CHAR *PostToken);
INT32 iPN_Proto_Send_PublishAck(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *Prefix,
		const UINT32 SerialNumber, const CHAR *CheckCode, const CHAR *EventName,
		const CHAR PublishResult, const CHAR *SubscribeToken,
		const CHAR *PostToken, const UINT16 Counter);
//// UnPublish
void iPN_Proto_Write_UnPublish(st_iPN_UnPublish *pUnPublish, const CHAR *Prefix,
		const UINT32 SerialNumber, const CHAR *CheckCode, const CHAR*AuthCode,
		const CHAR *EventName);
void iPN_Proto_Read_UnPublish(const st_iPN_UnPublish *pUnPublish, CHAR *Prefix,
		UINT32 *SerialNumber, CHAR *CheckCode, CHAR*AuthCode, CHAR *EventName);
INT32 iPN_Proto_Send_UnPublish(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *Prefix,
		const UINT32 SerialNumber, const CHAR *CheckCode, const CHAR*AuthCode,
		const CHAR *EventName, const UINT16 Counter);
//// UnPublishAck
void iPN_Proto_Write_UnPublishAck(st_iPN_UnPublishAck *pUnPublishAck,
		const CHAR *Prefix, const UINT32 SerialNumber, const CHAR *CheckCode,
		const CHAR *EventName, const CHAR UnPublishResult);
void iPN_Proto_Read_UnPublishAck(const st_iPN_UnPublishAck *pUnPublishAck,
		CHAR *Prefix, UINT32 *SerialNumber, CHAR *CheckCode, CHAR *EventName,
		CHAR *UnPublishResult);
INT32 iPN_Proto_Send_UnPublishAck(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *Prefix,
		const UINT32 SerialNumber, const CHAR *CheckCode, const CHAR *EventName,
		const CHAR UnPublishResult, const UINT16 Counter);
//// Subscribe
void iPN_Proto_Write_Subscribe(st_iPN_Subscribe *pSubscribe,
		const CHAR *SubscribeToken, const UINT32 SubscriberID,
		const UINT16 SubscribeDescriptionSize, const UINT32 TimeStamp,
		const CHAR *TableName);
void iPN_Proto_Read_Subscribe(const st_iPN_Subscribe *pSubscribe,
		CHAR *SubscribeToken, UINT32 *SubscriberID,
		UINT16 *SubscribeDescriptionSize, UINT32 *TimeStamp, CHAR *TableName);
INT32 iPN_Proto_Send_Subscribe(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *SubscribeToken,
		const UINT32 SubscriberID, const UINT16 SubscribeDescriptionSize,
		const UINT32 TimeStamp, const CHAR *TableName,
		const CHAR*SubscribeDescription, const UINT16 Counter);
//// SubscribeAck
void iPN_Proto_Write_SubscribeAck(st_iPN_SubscribeAck *pSubscribeAck,
		const CHAR *SubscribeToken, const CHAR SubscribeResult,
		const UINT32 SubscriberID);
void iPN_Proto_Read_SubscribeAck(const st_iPN_SubscribeAck *pSubscribeAck,
		CHAR *SubscribeToken, CHAR *SubscribeResult, UINT32 *SubscriberID);
INT32 iPN_Proto_Send_SubscribeAck(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *SubscribeToken,
		const CHAR SubscribeResult, const UINT32 SubscriberID,
		const UINT16 Counter);
//// UnSubscribe
void iPN_Proto_Write_UnSubscribe(st_iPN_UnSubscribe *pUnSubscribe,
		const CHAR *SubscribeToken, const UINT32 SubscriberID,
		const CHAR *TableName);
void iPN_Proto_Read_UnSubscribe(const st_iPN_UnSubscribe *pUnSubscribe,
		CHAR *SubscribeToken, UINT32 *SubscriberID, CHAR *TableName);
INT32 iPN_Proto_Send_UnSubscribe(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *SubscribeToken,
		const UINT32 SubscriberID, const CHAR *TableName, const UINT16 Counter);
//// UnSubscribeAck
void iPN_Proto_Write_UnSubscribeAck(st_iPN_UnSubscribeAck *pUnSubscribeAck,
		const CHAR *SubscribeToken, const CHAR UnSubscribeResult);
void iPN_Proto_Read_UnSubscribeAck(const st_iPN_UnSubscribeAck *pUnSubscribeAck,
		CHAR *SubscribeToken, CHAR *UnSubscribeResult);
INT32 iPN_Proto_Send_UnSubscribeAck(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *SubscribeToken,
		const CHAR UnSubscribeResult, const UINT16 Counter);
//// Post
void iPN_Proto_Write_Post(st_iPN_Post *pPost, const CHAR *PostToken,
		const UINT32 TimeStamp, const CHAR *AdditionalInfo);
void iPN_Proto_Read_Post(const st_iPN_Post *pPost, CHAR *PostToken,
		UINT32 *TimeStamp, CHAR *AdditionalInfo);
INT32 iPN_Proto_Send_Post(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *PostToken,
		const UINT32 TimeStamp, const CHAR *AdditionalInfo,
		const UINT16 Counter);
//// PostAck
void iPN_Proto_Write_PostAck(st_iPN_PostAck *pPostAck, const CHAR *PostToken,
		const CHAR PostResult);
void iPN_Proto_Read_PostAck(const st_iPN_PostAck *pPostAck, CHAR *PostToken,
		CHAR *PostResult);
INT32 iPN_Proto_Send_PostAck(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *PostToken,
		const CHAR PostResult, const UINT16 Counter);
//// QueryToken
void iPN_Proto_Write_QueryToken(st_iPN_QueryToken *pQueryToken, const CHAR *DID,
		const CHAR* EventName, const CHAR* QueryTokenPassword,
		const UINT32 TimeStamp);
void iPN_Proto_Read_QueryToken(const st_iPN_QueryToken *pQueryToken, CHAR *DID,
		CHAR *EventName, CHAR *QueryTokenPassword, UINT32 *TimeStamp);
INT32 iPN_Proto_Send_QueryToken(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *DID,
		const CHAR *EventName, const CHAR *QueryTokenPassword,
		const UINT32 TimeStamp, const UINT16 Counter);
//// QueryTokenAck
void iPN_Proto_Write_QueryTokenAck(st_iPN_QueryTokenAck *pQueryTokenAck,
		const CHAR *DID, const CHAR *EventName, const CHAR* SubscribeToken,
		const CHAR QueryTokenResult);
void iPN_Proto_Read_QueryTokenAck(const st_iPN_QueryTokenAck *pQueryTokenAck,
		CHAR *DID, CHAR *EventName, CHAR *SubscribeToken,
		CHAR *QueryTokenResult);
INT32 iPN_Proto_Send_QueryTokenAck(const INT32 skt, const CHAR *AESKey,
		const struct sockaddr_in *ToAddr, const CHAR *DID,
		const CHAR *EventName, const CHAR *SubscribeToken,
		const CHAR QueryTokenResult, const UINT16 Counter);

#endif  //#ifndef __INCLUDE_FILE_iPN_PROTOCOL
